package com.ken.mqspring.config;

import com.ken.constant.RabbitConstant;
import com.ken.mqspring.adapter.MessageDelegate;
import com.ken.mqspring.converter.ImageMessageConverter;
import com.ken.mqspring.converter.PDFMessageConverter;
import com.ken.mqspring.converter.TextMessageConverter;
import com.ken.mqspring.entity.Order;
import com.ken.mqspring.entity.Packaged;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.support.ConsumerTagStrategy;
import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter;
import org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


/**
 * spring加载RabbitMQ的配置文件
 * 将该目录加载到spring容器里
 * Created by renchongyu on 2018/11/20.
 */
@Configuration
@ComponentScan({"com.ken.mqspring.*"})
public class RabbitConfig {

    /**
     * 创建RabbitMQ连接，此处要是用Spring包里的类。
     * @return
     */
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(RabbitConstant.RABBITMQ_IP_PORT);
        connectionFactory.setUsername(RabbitConstant.RABBITMQ_USER_NAME);
        connectionFactory.setPassword(RabbitConstant.RABBITMQ_USER_PASSWORD);
        connectionFactory.setVirtualHost(RabbitConstant.RABBITMQ_VIRTUAL_HOST);
        return connectionFactory;
    }

    /**
     * 将rabbitAdmin加载到spring当中，注意参数名要与上面的方法名一致。
     * 因为Bean的注入某人以方法名做为注入名。
     * rabbitAdmin主要作用就是声明交换机、声明队列、绑定队列、清空队列等等基本操作
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);//此处一定要用true否则无法注入到Spring中
        return rabbitAdmin;
    }

    /**
     * 针对消费者配置
     * 1、设置交换机类型。 2.将队列绑定到交换机
     * FanoutExchange：将消息分发到绑定的队列，直连不经过routingKey，所以最快
     * HeadersExchange：可以设置头信息 key--value形式
     * DirectExchange:按照指定的routingKey分发到指定队列
     * TopicExchange:可以用通配符*#
     */

    @Bean
    public TopicExchange exchange001(){return new TopicExchange("topic001",true,false);}
    @Bean
    public Queue queue001(){return new Queue("queue001",true);}
    @Bean
    public Binding binding001(){return BindingBuilder.bind(queue001()).to(exchange001()).with("spring.*");}
    @Bean
    public TopicExchange exchange002(){return new TopicExchange("topic002",true,false);}
    @Bean
    public Queue queue002(){return new Queue("queue002",true);}
    @Bean
    public Binding binding002(){return BindingBuilder.bind(queue002()).to(exchange002()).with("rabbit.*");}
    @Bean
    public Queue queue003(){return new Queue("queue003",true);}
    @Bean
    public Binding binding003(){return BindingBuilder.bind(queue003()).to(exchange001()).with("mq.*");}

    @Bean
    public Queue queue_image(){
        return new Queue("image_queue",true);
    }
    @Bean
    public Queue queue_pdf(){
        return new Queue("pdf_queue",true);
    }

    /**
     * 创建rabbit模板，注入到Spring中
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

    /**
     * 创建rabbit动态配置，消息监听器
     * @param connectionFactory
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        //批量队列
        container.setQueues(queue001(),queue002(),queue003(),queue_image(),queue_pdf());
        //设置消费者数量
        container.setConcurrentConsumers(1);
        //设置最大消费者数量
        container.setMaxConcurrentConsumers(5);
        //是否可重复队列
        container.setDefaultRequeueRejected(false);
        //签收机制
        container.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //自定义标签
        container.setConsumerTagStrategy(new ConsumerTagStrategy() {
            @Override
            public String createConsumerTag(String queue) {
                return queue + "_"+ UUID.randomUUID().toString();
            }
        });
        /**
         //默认监听消息处理
        container.setMessageListener(new ChannelAwareMessageListener() {
            @Override
            public void onMessage(Message message,Channel channel) {
                System.out.println("消费者 = "+new String(message.getBody()));

            }
        });
         */

        //自定义消息适配器消息处理
        /**
         * 自定义适配器方式一、
         * 使用自定义类接收消息，默认方法是handleMessage(byte[] messageBody);
         * 如果想换一个方法可以如下setDefaultListenerMethod
         * 如果想换传入参数，则需要一个类实现MessageConverter接口
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("consumerMessage");
        adapter.setMessageConverter(new TextMessageConverter());
        container.setMessageListener(adapter);
         */

        /**
         * 自定义适配器方式二、
         * 利用队列名词、方法名进行适配。(Map)
         * 队列名KEY,  方法名VALUE
         * 注意方法顺序，先setMessageConverter、后setQueueOrTagToMethodName

        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setMessageConverter(new TextMessageConverter());
        Map<String,String> map = new HashMap<>();
        map.put("queue001","method1");
        map.put("queue002","method2");
        adapter.setQueueOrTagToMethodName(map);
        container.setMessageListener(adapter);
         */
        //自定义转换器：支持：String、json、java对象映射、二进制图片、pdf、ppt、流媒体
        /**
         * 自定义转换器1.1、支持json格式的转换器
         * Jackson2JsonMessageConverter支持Map接收

        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("consumeMessage");
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        adapter.setMessageConverter(jackson2JsonMessageConverter);
        container.setMessageListener(adapter);
         */


        /**
         * 自定义转换器1.2、支持json格式转换为java类的转换器
         * DefaultJackson2JavaTypeMapper支持java类接收
         *

        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("consumeMessage");
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        //告诉转换器用java类
        DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();
        jackson2JsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
        adapter.setMessageConverter(jackson2JsonMessageConverter);
        container.setMessageListener(adapter);
         */


        /**
         * 自定义转换器1.3、支持json格式转换为多个java类的转换器
         * DefaultJackson2JavaTypeMapper支持java类接收
         * DefaultJackson2JavaTypeMapper可以放入Map<String,Class>支持多个java类转换
         * 需要给每个转转单独实现消息处理。

        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("consumeMessage");
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();
        Map<String,Class<?>> map = new HashMap<>();
        map.put("order",Order.class);
        map.put("packaged", Packaged.class);
        javaTypeMapper.setIdClassMapping(map);
        jackson2JsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
        adapter.setMessageConverter(jackson2JsonMessageConverter);
        container.setMessageListener(adapter);
         */

        /**
         * 1.4一些不是很常用的类型：img、pdf、ppt等等
         * 全局转换器ContentTypeDelegatingMessageConverter

        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("consumeMessage");
        //全局转换器,
        ContentTypeDelegatingMessageConverter allConverter = new ContentTypeDelegatingMessageConverter();
        //text类型
        TextMessageConverter textConverter = new TextMessageConverter();
        allConverter.addDelegate("text",textConverter);
        allConverter.addDelegate("html/text",textConverter);
        allConverter.addDelegate("xml/text",textConverter);
        allConverter.addDelegate("text/plain",textConverter);

        //jason类型
        Jackson2JsonMessageConverter jsonConverter = new Jackson2JsonMessageConverter();
        allConverter.addDelegate("json",jsonConverter);
        allConverter.addDelegate("application/json",jsonConverter);

        //图片类型
        ImageMessageConverter imageConverter = new ImageMessageConverter();
        allConverter.addDelegate("image",imageConverter);
        allConverter.addDelegate("image/png",imageConverter);

        //pdf类型
        PDFMessageConverter pdfConverter = new PDFMessageConverter();
        allConverter.addDelegate("application/pdf",pdfConverter);

        //最后别忘了加到适配器里
        adapter.setMessageConverter(allConverter);
        container.setMessageListener(adapter);
         */
        return container;
    }

}
